<!DOCTYPE html>
<html lang="en">
  <head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
<meta name="description" content="Tutorial for getting started with GoJS."/> 
<link rel="stylesheet" href="../assets/css/style.css"/> 
<!-- Copyright 1998-2021 by Northwoods Software Corporation. -->    <title> GoJS Interactivity </title>
    <link rel="stylesheet" href="../assets/css/prism.css"  />
    
    <script src="../release/go.js"></script>
  </head>
  <body>
  <nav id="navTop" class="w-full z-30 top-0 text-white bg-nwoods-primary">
    <div class="w-full container max-w-screen-lg mx-auto flex flex-wrap sm:flex-nowrap items-center justify-between mt-0 py-2">
      <div class="md:pl-4">
        <a class="text-white hover:text-white no-underline hover:no-underline
        font-bold text-2xl lg:text-4xl rounded-lg hover:bg-nwoods-secondary " href="../">
          <h1 class="mb-0 p-1 ">GoJS</h1>
        </a>
      </div>
      <button id="topnavButton" class="rounded-lg sm:hidden focus:outline-none focus:ring" aria-label="Navigation">
        <svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
          <path id="topnavOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
          <path id="topnavClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
        </svg>
      </button>
      <div id="topnavList" class="hidden lg:text-base sm:block items-center w-auto mt-0 text-white p-0 z-20">
        <ul class="list-reset list-none font-semibold flex justify-end flex-wrap sm:flex-nowrap items-center px-0 pb-0">
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../learn/">Learn</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../samples/">Samples</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../intro/">Intro</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../api/">API</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/products/register.html">Register</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../download.html">Download</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://forum.nwoods.com/c/gojs/11">Forum</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/contact.html"
           target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/sales/index.html"
           target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a></li>
        </ul>
      </div>
    </div>
    <hr class="border-b border-gray-600 opacity-50 my-0 py-0" />
  </nav>
    
    <div class="md:flex flex-col md:flex-row md:min-h-screen w-full max-w-screen-xl mx-auto">
      
    <div id="navSide" class="flex flex-col w-full md:w-40 lg:w-48 text-gray-700 bg-white flex-shrink-0">
      <div class="flex-shrink-0 px-8 py-4">
        <button id="navButton" class="rounded-lg md:hidden focus:outline-none focus:ring" aria-label="Navigation">
          <svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
            <path id="navOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
            <path id="navClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
          </svg>
        </button>
      </div>
      <nav id="navList" class="min-h-screen hidden md:block sidebar-nav flex-grow px-1 lg:px-4 pb-4 md:pb-0 md:overflow-y-auto break-words">
  <a href="../learn/index.html">Get Started</a>
  <a href="../learn/graphObject.html">Manipulating GraphObjects</a>
  <a href="../learn/interactivity.html">Interacting with Diagrams</a>
      </nav>
    </div>      
      <div class="pt-4 px-2 md:px-0 lg:px-4 pb-16 w-full overflow-hidden">

<h1>Interacting with Diagrams</h1>

<h2 id="BuiltinGoJSInteractivity">Built-in GoJS Interactivity</h2>

<p>
  <b>GoJS</b> implements a number of common editing operations, such as manipulating parts
  (moving, adding, copying, cutting, and deleting).
  These editing abilities are accessible via mouse (or touch) and keyboard by default,
  and can also be invoked programmatically in JavaScript.
</p>

<p>
  The following Diagram defines a node template and has four nodes in its model:
</p>

<pre class="lang-js"><code>
var $ = go.GraphObject.make;

myDiagram =
  $(go.Diagram, "myDiagramDiv",
    { "undoManager.isEnabled": true });

// define a simple Node template
myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    $(go.Shape, "Rectangle",
      // don't draw any outline
      { stroke: null },
      // the Shape.fill comes from the Node.data.color property
      new go.Binding("fill", "color")),
    $(go.TextBlock,
      // leave some space around larger-than-normal text
      { margin: 6, font: "18px sans-serif" },
      // the TextBlock.text comes from the Node.data.text property
      new go.Binding("text"))
  );

myDiagram.model = new go.GraphLinksModel(
  [ // there will be a Node for each data object in this nodeDataArray
    { key: 1, text: "Alpha", color: "lightblue" },
    { key: 2, text: "Beta", color: "orange" },
    { key: 3, text: "Gamma", color: "lightgreen" },
    { key: 4, text: "Delta", color: "pink" }
  ]);
</code></pre>

<!-- LIVE -->
<div id="myDiagramDiv" class="diagramStyling" style="width:700px; height:150px"></div>
<script>
  var $ = go.GraphObject.make;

  var myDiagram =
    $(go.Diagram, "myDiagramDiv",
      { "undoManager.isEnabled": true });

  myDiagram.nodeTemplate =
    $(go.Node, "Auto",
      $(go.Shape, "Rectangle",
        { stroke: null },
        new go.Binding("fill", "color")),
      $(go.TextBlock,
        { margin: 6, font: "18px sans-serif" },
        new go.Binding("text"))
    );

  myDiagram.model = new go.GraphLinksModel(
    [ // there will be a Node for each data object in this nodeDataArray
      { key: 1, text: "Alpha", color: "lightblue" },
      { key: 2, text: "Beta", color: "orange" },
      { key: 3, text: "Gamma", color: "lightgreen" },
      { key: 4, text: "Delta", color: "pink" }
    ]);
</script>

<p>
  Out of the box, several interactions are available:
</p>
<ul>
  <li>
    Click a node to select it.
    Press and drag on a node to move it around.
    Or press and drag in the diagram background to pan the entire Diagram.
  </li>
  <li>
    Common keyboard shortcuts such as <code>CTRL-C</code>, <code>CTRL-V</code>, <code>CTRL-X</code>
    will copy, paste, and cut diagram parts, respectively.
  </li>
  <li>
    Drag-and-hold allows you to create a selection box for selecting multiple nodes.
    CTRL-clicking on nodes allows you to toggle their selection.
  </li>
  <li>
    Since the Diagram's undoManager was enabled, <code>CTRL-Z</code> and <code>CTRL-Y</code> will undo and redo operations.
    Panning (scrolling) and selection are not considered undoable operations.
  </li>
</ul>

<p>
  By setting a few properties you can expose more interaction to a user:
</p>

<pre class="lang-js"><code>
var $ = go.GraphObject.make;

var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      // allow double-click in background to create a new node
      "clickCreatingTool.archetypeNodeData": { key: "Node", color: "white" },
      // allow Ctrl-G to group selected nodes
      "commandHandler.archetypeGroupData": { text: "Group", isGroup: true },
      // have mouse wheel events zoom in and out instead of scroll up and down
      "toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom,
      "undoManager.isEnabled": true // enable undo &amp; redo
    });

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    $(go.Shape, "Rectangle",
      { stroke: null },
      new go.Binding("fill", "color")),
    $(go.TextBlock,
      { margin: 6, font: "18px sans-serif", editable: true },
      new go.Binding("text").makeTwoWay())
  );

myDiagram.groupTemplate =
  $(go.Group, "Vertical",
    { ungroupable: true }, // allow Ctrl-Shift-G to ungroup a selected Group.
    $(go.TextBlock,
      { font: "bold 12pt sans-serif" },
      new go.Binding("text")),
    $(go.Panel, "Auto",
      $(go.Shape, { fill: "transparent" }),
      $(go.Placeholder, { padding: 10 })
    )
  );

myDiagram.model = new go.GraphLinksModel(
  [
    { key: 1, text: "Alpha", color: "lightblue" },
    { key: 2, text: "Beta", color: "orange" },
    { key: 3, text: "Gamma", color: "lightgreen", group: 5 },
    { key: 4, text: "Delta", color: "pink", group: 5 },
    { key: 5, text: "Group1", isGroup: true }
  ]);
</code></pre>

<!-- LIVE -->
<div id="myDiagramDiv2" class="diagramStyling" style="width:700px; height:250px"></div>
<script>
  var $ = go.GraphObject.make;

  var myDiagram =
    $(go.Diagram, "myDiagramDiv2",
      {
        // allow double-click in background to create a new node
        "clickCreatingTool.archetypeNodeData": { key: "Node", color: "white" },
        // allow Ctrl-G to group selected nodes
        "commandHandler.archetypeGroupData": { text: "Group", isGroup: true },
        // have mouse wheel events zoom in and out instead of scroll up and down
        "toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom,
        "undoManager.isEnabled": true // enable undo & redo
      });

  myDiagram.nodeTemplate =
    $(go.Node, "Auto",
      $(go.Shape, "Rectangle",
        { stroke: null },
        new go.Binding("fill", "color")),
      $(go.TextBlock,
        { margin: 6, font: "18px sans-serif", editable: true },
        new go.Binding("text").makeTwoWay())
    );

  myDiagram.groupTemplate =
    $(go.Group, "Vertical",
      { ungroupable: true }, // allow Ctrl-Shift-G to ungroup a selected Group.
      $(go.TextBlock,
        { font: "bold 12pt sans-serif" },
        new go.Binding("text")),
      $(go.Panel, "Auto",
        $(go.Shape, { fill: "transparent" }),
        $(go.Placeholder, { padding: 10 })
      )
    );

  myDiagram.model = new go.GraphLinksModel(
    [
      { key: 1, text: "Alpha", color: "lightblue" },
      { key: 2, text: "Beta", color: "orange" },
      { key: 3, text: "Gamma", color: "lightgreen", group: 5 },
      { key: 4, text: "Delta", color: "pink", group: 5 },
      { key: 5, text: "Group1", isGroup: true }
    ]);
</script>

<p>
  <ul>
    <li>
      <code>ClickCreatingTool.archetypeNodeData</code> allows a double-click in the background to create
      a new node with the specified data.
    </li>
    <li>
      <code>CommandHandler.archetypeGroupData</code> allows <code>CTRL-G</code> to group a selection of nodes.
    </li>
    <li>
      <code>Group.ungroupable</code> allows <code>CTRL-SHIFT-G</code> to ungroup a selected group.
    </li>
    <li>
      <code>ToolManager.mouseWheelBehavior</code> allows the mouse wheel to zoom instead of scroll by default.
      You can toggle this property by clicking on the mouse-wheel.
      On touch devices, pinch-zooming is enabled by default.
    </li>
    <li>
      <code>TextBlock.editable</code> in the <code>TextBlock</code> definition allows the text to be edited in place.
      Select a node and then click on the text, or press F2, to begin text editing.
      Click anywhere else on the diagram or press <code>Tab</code> to finish editing text.
    </li>
  </ul>
</p>

<p>
  These interactions (and more!) are all present in the <a href="../samples/basic.html">basic.html sample</a>.
  Be sure to also see the <a href="../intro/commands.html">Intro page on GoJS commands</a>.
</p>

<p>
  You can disable portions of Diagram interactivity with several properties,
  depending on what you want to allow users to do.
  See the <a href="../intro/permissions.html">Intro page on GoJS permissions</a> for more.
</p>

<h2 id="ContextMenus">Context Menus</h2>

<p>
  <b>GoJS</b> provides a mechanism for you to define context menus for any object or for the Diagram itself.
  In the example below, two context menus are defined, one on the Node template (with one button) and
  one on the Diagram (with two buttons).
</p>

<pre class="lang-js"><code>
var $ = go.GraphObject.make;

var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    { "undoManager.isEnabled": true });

// this function is called when the context menu button is clicked
function nodeClicked(e, obj) {
  alert('node ' + obj.part.data.key + ' was clicked');
}

// defines a context menu to be referenced in the node template
var contextMenuTemplate =
  $(go.Adornment, "Vertical",
    $("ContextMenuButton",
      $(go.TextBlock, "Click me!"),
      { click: nodeClicked })
    // more ContextMenuButtons would go here
  );

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    { contextMenu: contextMenuTemplate }, // set the context menu
    $(go.Shape, "Rectangle",
      { stroke: null },
      new go.Binding("fill", "color")),
    $(go.TextBlock,
      { margin: 6, font: "18px sans-serif" },
      new go.Binding("text"))
  );

// this function alerts the current number of nodes in the Diagram
function countNodes(e, obj) {
  alert('there are ' + e.diagram.nodes.count + ' nodes');
}

// this function creates a new node and inserts it at the last event's point
function addNode(e, obj) {
  var data = { text: "Node", color: "white" };
  // do not need to set "key" property -- addNodeData will assign it automatically
  e.diagram.model.addNodeData(data);
  var node = e.diagram.findPartForData(data);
  node.location = e.diagram.lastInput.documentPoint;
}

myDiagram.contextMenu =
  $(go.Adornment, "Vertical",
    $("ContextMenuButton",
      $(go.TextBlock, "Count Nodes"),
      { click: countNodes }),
    $("ContextMenuButton",
      $(go.TextBlock, "Add Node"),
      { click: addNode })
    // more ContextMenuButtons would go here
  );

myDiagram.model = new go.GraphLinksModel(
  [
    { key: 1, text: "Alpha", color: "lightblue" },
    { key: 2, text: "Beta", color: "orange" }
  ]);
</code></pre>

<!-- LIVE -->
<div id="myDiagramDiv3" class="diagramStyling" style="width:700px; height:150px"></div>
<script>
  var $ = go.GraphObject.make;

  var myDiagram =
    $(go.Diagram, "myDiagramDiv3",
      { "undoManager.isEnabled": true });

  // this function is called when the context menu button is clicked
  function nodeClicked(e, obj) {
    alert('node ' + obj.part.data.key + ' was clicked');
  }

  // defines a context menu to be referenced in the node template
  var contextMenuTemplate =
    $(go.Adornment, "Vertical",
      $("ContextMenuButton",
        $(go.TextBlock, "Click me!"),
        { click: nodeClicked })
      // more ContextMenuButtons would go here
    );

  myDiagram.nodeTemplate =
    $(go.Node, "Auto",
      { contextMenu: contextMenuTemplate }, // set the context menu
      $(go.Shape, "Rectangle",
        { stroke: null },
        new go.Binding("fill", "color")),
      $(go.TextBlock,
        { margin: 6, font: "18px sans-serif" },
        new go.Binding("text"))
    );

  // this function alerts the current number of nodes in the Diagram
  function countNodes(e, obj) {
    alert('there are ' + e.diagram.nodes.count + ' nodes');
  }

  // this function creates a new node and inserts it at the last event's point
  function addNode(e, obj) {
    var data = { text: "Node", color: "white" };
    // do not need to set "key" property -- addNodeData will assign it automatically
    e.diagram.model.addNodeData(data);
    var node = e.diagram.findPartForData(data);
    node.location = e.diagram.lastInput.documentPoint;
  }

  myDiagram.contextMenu =
    $(go.Adornment, "Vertical",
      $("ContextMenuButton",
        $(go.TextBlock, "Count Nodes"),
        { click: countNodes }),
      $("ContextMenuButton",
        $(go.TextBlock, "Add Node"),
        { click: addNode })
      // more ContextMenuButtons would go here
    );

  myDiagram.model = new go.GraphLinksModel(
    [
      { key: 1, text: "Alpha", color: "lightblue" },
      { key: 2, text: "Beta", color: "orange" }
    ]);
</script>

<p>
  If you right-click (or long-tap on a touch device) on a Node or the Diagram, you will see the <b>GoJS</b> context menu
  appear with the defined options.
</p>

<p>
  The <a href="../samples/basic.html">basic.html sample</a> contains more complex context menu examples.
  See the <a href="../intro/contextmenus.html">Intro page on GoJS context menus</a> for more discussion.
</p>

<h2 id="LinkInteractions">Link interactions</h2>

<p>
  <b>GoJS</b> lets users draw new links by dragging out from a port.
  Users can reconnect existing links by selecting one and dragging one of its handles.
  To enable these tools, some properties need to be set:
</p>

<pre class="lang-js"><code>
myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    $(go.Shape, "Rectangle",
      {
        stroke: null,
        portId: "",
        cursor: "pointer",
        fromLinkable: true, fromLinkableSelfNode: true, fromLinkableDuplicates: true,
        toLinkable: true, toLinkableSelfNode: true, toLinkableDuplicates: true
      },
      new go.Binding("fill", "color")),
    $(go.TextBlock,
      { margin: 6, font: "18px sans-serif" },
      new go.Binding("text"))
  );

myDiagram.linkTemplate =
  $(go.Link,
    {
      // allow the user to reconnnect existing links:
      relinkableFrom: true, relinkableTo: true,
      // draw the link path shorter than normal,
      // so that it does not interfere with the appearance of the arrowhead
      toShortLength: 2
    },
    $(go.Shape,
      { strokeWidth: 2 }),
    $(go.Shape,
      { toArrow: "Standard", stroke: null })
  );

myDiagram.model = new go.GraphLinksModel(
  [
    { key: "Alpha", color: "lightblue" },
    { key: "Beta", color: "orange" },
    { key: "Gamma", color: "lightgreen" },
    { key: "Delta", color: "pink" }
  ],
  [
    { from: 1, to: 2 },
    { from: 1, to: 4 }
  ]);
</code></pre>

<!-- LIVE -->
<div id="myDiagramDiv4" class="diagramStyling" style="width:700px; height:150px"></div>
<script>
  var $ = go.GraphObject.make;

  var myDiagram =
    $(go.Diagram, "myDiagramDiv4",
      { "undoManager.isEnabled": true });

  myDiagram.nodeTemplate =
    $(go.Node, "Auto",
      $(go.Shape, "Rectangle",
        {
          stroke: null,
          portId: "",
          cursor: "pointer",
          fromLinkable: true, fromLinkableSelfNode: true, fromLinkableDuplicates: true,
          toLinkable: true, toLinkableSelfNode: true, toLinkableDuplicates: true
        },
        new go.Binding("fill", "color")),
      $(go.TextBlock,
        { margin: 10, font: "18px sans-serif" },
        new go.Binding("text"))
    );

  myDiagram.linkTemplate =
    $(go.Link,
      {
        // allow the user to relink existing links:
        relinkableFrom: true, relinkableTo: true,
        // draw the link path shorter than normal,
        // so that it does not interfere with the appearance of the arrowhead
        toShortLength: 2
      },
      $(go.Shape,
        { strokeWidth: 2 }),
      $(go.Shape,
        { toArrow: "Standard", stroke: null })
    );

  myDiagram.model = new go.GraphLinksModel(
  [
    { key: 1, text: "Alpha", color: "lightblue" },
    { key: 2, text: "Beta", color: "orange" },
    { key: 3, text: "Gamma", color: "lightgreen" },
    { key: 4, text: "Delta", color: "pink" }
  ],
  [
    { from: 1, to: 2 },
    { from: 1, to: 4 }
  ]);
</script>

<p>
  In the above example:
</p>
<ul>
  <li>
    The <code>Shape</code> has its <code>portId</code> set to make it the port instead of the entire node.
    Then several <code>...linkable</code> properties are set, allowing each node to link to itself and to others.
    You may not need to set all of those properties on your ports in your node templates.
  </li>
  <li>
    To create a new link to another node, drag from the port (the edge of the Shape that is not
    behind the TextBlock) to any node, including itself.
  </li>
  <li>
    In the link template, <code>relinkable...</code> properties are set, so that when the link is selected,
    it shows handles that can be dragged in order to reconnect the link with a different node.
  </li>
</ul>

<p>
  <b>GoJS</b> allows linking and re-linking to abide by custom criteria in which source and destination nodes are valid.
  You can read about this in the <a href="../intro/validation.html">Intro page on Validation</a>.
</p>

<p>
  <b>GoJS</b> links have many interesting properties that are covered in depth in the
  <a href="../intro/links.html">Intro page on Links</a> and on the following pages.
</p>

<p>
  You may want to read more tutorials, such as the <a href="index.html">Learn GoJS</a> tutorial
  and the <a href="graphObject.html">GraphObject Manipulation</a> tutorial
  You can also watch tutorials on <a href="https://www.youtube.com/channel/UC9We8EoX596-6XFjJDtZIDg">YouTube</a>.
</p>


      </div>
    </div>
  
  <div class="bg-nwoods-primary">
    <section class="max-w-screen-lg text-white container mx-auto py-2 px-12">
      <p id="version" class="leading-none mb-2 my-4">GoJS</p>
    </section>
  </div><footer class="bg-nwoods-primary text-white">
  <div class="container max-w-screen-lg mx-auto  px-8">
    <div class="w-full py-6">

        <div class="max-w-screen-lg xl:max-w-screen-xl mx-auto px-4 sm:px-6 md:px-8">
          <ul class="text-sm font-medium pb-14 sm:pb-20 grid grid-cols-1 sm:grid-cols-3 gap-y-10">
            <li class="list-none row-span-2">
              <h2 class="text-base font-semibold tracking-wide">GoJS</h2>
              <ul class="list-none space-y-4 md:space-y-1 px-0">
                <li>
                  <a href="../samples/index.html">Samples</a>
                </li>
                <li>
                  <a href="../learn/index.html">Learn</a>
                </li>
                <li>
                  <a href="../intro/index.html">Intro</a>
                </li>
                <li>
                  <a href="../api/index.html">API</a>
                </li>
                <li>
                  <a href="../changelog.html">Changelog</a>
                </li>
                <li>
                  <a href="https://github.com/NorthwoodsSoftware/GoJS">GitHub</a>
                </li>
              </ul>
            </li>
            <li class="list-none row-span-2">
              <h2 class="text-base font-semibold tracking-wide">Support</h2>
              <ul class="list-none space-y-4 md:space-y-1 px-0">
                <li>
                  <a href="https://www.nwoods.com/contact.html"
                  target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a>
                </li>
                <li>
                  <a href="https://forum.nwoods.com/c/gojs">Forum</a>
                </li>
                <li>
                  <a href="https://www.nwoods.com/app/activate.aspx?sku=gojs">Activate</a>
                </li>
                <li>
                  <a href="https://www.nwoods.com/sales/index.html"
                  target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a>
                </li>
                <li>
                  <a href="https://www.youtube.com/channel/UC9We8EoX596-6XFjJDtZIDg">Videos</a>
                </li>
              </ul>
            </li>
            <li class="list-none row-span-2">
              <h2 class="text-base font-semibold tracking-wide">Company</h2>
              <ul class="list-none space-y-4 md:space-y-1 px-0">
                <li>
                  <a href="https://www.nwoods.com">Northwoods</a>
                </li>
                <li>
                  <a href="https://www.nwoods.com/about.html">About Us</a>
                </li>
                <li>
                  <a href="https://www.nwoods.com/contact.html">Contact Us</a>
                </li>
                <li>
                  <a href="https://twitter.com/northwoodsgo">Twitter</a>
                </li>

              </ul>
            </li>
          </ul>


      <p class="text-sm text-gray-100 md:mb-6">
        Copyright 1998-2021 <a class="text-white" href="https://www.nwoods.com">Northwoods Software</a>
      </p>
    </div>
  </div>
</footer>  </body>

<script async src="https://www.googletagmanager.com/gtag/js?id=UA-1506307-5"></script> 
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date()); gtag('config', 'UA-1506307-5');
  var getOutboundLink = function(url, label) {
    gtag('event', 'click', {
      'event_category': 'outbound',
      'event_label': label,
      'transport_type': 'beacon'
    });
  }

  // topnav
  var topButton = document.getElementById("topnavButton");
  var topnavList = document.getElementById("topnavList");
  topButton.addEventListener("click", function() {
    this.classList.toggle("active");
    topnavList.classList.toggle("hidden");
    document.getElementById("topnavOpen").classList.toggle("hidden");
    document.getElementById("topnavClosed").classList.toggle("hidden");
  });
</script>
  <script src="../assets/js/prism.js"></script>
  <script src="../assets/js/goDoc.js"></script>
  <script>
    document.addEventListener("DOMContentLoaded", function() {
      if (window.go) document.getElementById('version').textContent = "GoJS version " + go.version;
      if (window.goDoc) window.goDoc();
    });
  </script>
</html>